package com.dobbinsoft.iotechn.user.service.biz;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dobbinsoft.iotechn.core.constant.Const;
import com.dobbinsoft.iotechn.core.exception.CoreExceptionDefinition;
import com.dobbinsoft.iotechn.core.exception.ServiceException;
import com.dobbinsoft.iotechn.core.exception.ThirdPartServiceException;
import com.dobbinsoft.iotechn.core.model.UserSession;
import com.dobbinsoft.iotechn.data.compent.CacheComponent;
import com.dobbinsoft.iotechn.user.api.biz.UserBizService;
import com.dobbinsoft.iotechn.user.constant.UserConst;
import com.dobbinsoft.iotechn.user.domain.UserDO;
import com.dobbinsoft.iotechn.user.mapper.UserMapper;
import com.dobbinsoft.iotechn.user.properties.FrameworkWxProperties;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: rize
 * Date: 2020/3/17
 * Time: 15:13
 */
@Service("userBizService")
public class UserBizServiceImpl implements UserBizService {

    private OkHttpClient okHttpClient = new OkHttpClient();

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StringRedisTemplate userRedisTemplate;

    @Autowired
    private FrameworkWxProperties frameworkWxProperties;

    @Autowired
    private CacheComponent cacheComponent;

    private static final Logger logger = LoggerFactory.getLogger(UserBizServiceImpl.class);

    @Override
    public String getWxMiniAccessToken() throws ServiceException {
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + frameworkWxProperties.getMiniAppId() + "&secret=" + frameworkWxProperties.getMiniAppSecret();
        return getAccessToken(UserConst.CA_MINI_WECHAT_ACCESS, url);
    }

    /**
     * 获取WX系 AccessToken 抽取方法
     * @param key
     * @param url
     * @return
     * @throws ServiceException
     */
    private String getAccessToken(String key, String url) throws ServiceException {
        String access_token = cacheComponent.getRaw(key);
        if (StringUtils.isEmpty(access_token)) {
            String accessJson = null;
            try {
                accessJson = okHttpClient.newCall(
                        new Request.Builder()
                                .url(url)
                                .get()
                                .build()).execute().body().string();
            } catch (IOException e) {
                throw new ThirdPartServiceException(CoreExceptionDefinition.THIRD_PART_SERVICE_IO_EXCEPTION);
            }
            JSONObject jsonObject = JSONObject.parseObject(accessJson);
            access_token = jsonObject.getString("access_token");
            if (!StringUtils.isEmpty(access_token)) {
                Integer expires_in = jsonObject.getInteger("expires_in");
                Integer cacheExpireSec = expires_in * 4 / 5;
                cacheComponent.putRaw(key, access_token, cacheExpireSec);
            } else {
                throw new ThirdPartServiceException(jsonObject.getString("errmsg"), jsonObject.getInteger("errcode"));
            }
        }
        return access_token;
    }

    @Override
    public UserSession getUserSessionByAccessToken(String accessToken) {
        String userJson = userRedisTemplate.opsForValue().get(Const.USER_REDIS_PREFIX + accessToken);
        if (!StringUtils.isEmpty(userJson)) {
            UserSession userSession = JSONObject.parseObject(userJson, UserSession.class);
            userRedisTemplate.expire(Const.USER_REDIS_PREFIX + accessToken, Const.USER_SESSION_EXPIRE_MINUTES, TimeUnit.MINUTES);
            return userSession;
        }
        return null;
    }

    @Override
    public UserDO getUserById(Long userId) throws ServiceException {
        return userMapper.selectById(userId);
    }

    @Override
    @DS(Const.DB_S)
    public List<UserDO> getUsersNicknameAndAvatar(List<Long> userIds) {
        return userMapper.selectList(new QueryWrapper<UserDO>().select("id", "nickname", "avatar_url").in("id", userIds));
    }

    @Override
    public Set<String> getUserSessionSetById(Long userId) {
        return userRedisTemplate.keys(Const.USER_REDIS_PREFIX + userId + "-*").stream().map(item -> item.replace(Const.USER_REDIS_PREFIX, "")).collect(Collectors.toSet());
    }

}
